package com.socket.nio.nio.chat.example2.client;

import com.socket.nio.nio.chat.example2.message.*;
import com.socket.nio.nio.chat.example2.protocol.MessageCodecSharable;
import com.socket.nio.nio.chat.example2.protocol.ProcotolFrameDecoder;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import lombok.extern.slf4j.Slf4j;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;

@Slf4j
public class ChatClient {
  public static void main(String[] args) {
    NioEventLoopGroup group = new NioEventLoopGroup();
//    LoggingHandler LOGGING_HANDLER = new LoggingHandler(LogLevel.DEBUG);
    MessageCodecSharable MESSAGE_CODEC = new MessageCodecSharable();
    // 线程间通信
    CountDownLatch WAIT_FOR_LOGIN = new CountDownLatch(1);
    // 登录成功标识
    AtomicBoolean LOGIN_SUCCESS = new AtomicBoolean(false);
    try {
      Bootstrap bootstrap = new Bootstrap();
      bootstrap.channel(NioSocketChannel.class);
      bootstrap.group(group);
      bootstrap.handler(new ChannelInitializer<SocketChannel>() {
        @Override
        protected void initChannel(SocketChannel ch) throws Exception {
          ch.pipeline().addLast(new ProcotolFrameDecoder());
//          ch.pipeline().addLast(LOGGING_HANDLER);
          ch.pipeline().addLast(MESSAGE_CODEC);
          ch.pipeline().addLast("client handler", new ChannelInboundHandlerAdapter() {
            // 连接建立后触发
            @Override
            public void channelActive(ChannelHandlerContext ctx) {
              new Thread(() -> {
                Scanner scanner = new Scanner(System.in);
                System.out.println("请输入用户名：");
                String userName = scanner.nextLine();
                System.out.println("请输入密码：");
                String password = scanner.nextLine();

                LoginRequestMessage message = LoginRequestMessage.builder()
                    .username(userName)
                    .password(password)
                    .build();
                ctx.writeAndFlush(message);

                try {
                  WAIT_FOR_LOGIN.await();
                } catch (InterruptedException e) {
                  throw new RuntimeException(e);
                }
                // 如果登录不成功
                if (!LOGIN_SUCCESS.get()) {
                  ctx.channel().close();
                  return;
                }

                while (true) {
                  System.out.println("==================================");
                  System.out.println("send [username] [content]");
                  System.out.println("gsend [group name] [content]");
                  System.out.println("gcreate [group name] [m1,m2,m3...]");
                  System.out.println("gmembers [group name]");
                  System.out.println("gjoin [group name]");
                  System.out.println("gquit [group name]");
                  System.out.println("quit");
                  System.out.println("==================================");
                  String command = scanner.nextLine();
                  String[] s = command.split(" ");
                  switch (s[0]) {
                    case "send":
                      ctx.writeAndFlush(ChatRequestMessage.builder()
                          .from(userName)
                          .to(s[1])
                          .content(s[2])
                          .build());
                      break;
                    case "gsend":
                      ctx.writeAndFlush(GroupChatRequestMessage.builder()
                          .from(userName)
                          .groupName(s[1])
                          .content(s[2])
                          .build());
                      break;
                    case "gcreate":
                      Set<String> set = new HashSet<>(Arrays.asList(s[2].split(",")));
                      set.add(userName);
                      ctx.writeAndFlush(GroupCreateRequestMessage.builder()
                          .groupName(s[1])
                          .members(set)
                          .build());
                      break;
                    case "gmembers":
                      ctx.writeAndFlush(GroupMembersRequestMessage.builder()
                          .groupName(s[1])
                          .build());
                      break;
                    case "gjoin":
                      ctx.writeAndFlush(GroupJoinRequestMessage.builder()
                          .username(userName)
                          .groupName(s[1])
                          .build());
                      break;
                    case "gquit":
                      ctx.writeAndFlush(GroupQuitRequestMessage.builder()
                          .username(userName)
                          .groupName(s[1])
                          .build());
                      break;
                    case "quit":
                      ctx.channel().close();
                      return;
                  }
                }


              }, "system in").start();
            }

            @Override
            public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
              log.debug("msg: {}", msg);

              if (msg instanceof LoginResponseMessage) {
                LoginResponseMessage responseMessage = (LoginResponseMessage) msg;
                if (responseMessage.isSuccess()) {
                  LOGIN_SUCCESS.set(true);
                }
              }

              //唤醒 system in 的线程
              WAIT_FOR_LOGIN.countDown();
            }
          });
        }
      });
      Channel channel = bootstrap.connect("localhost", 8080).sync().channel();
      channel.closeFuture().sync();
    } catch (Exception e) {
      log.error("client error", e);
    } finally {
      group.shutdownGracefully();
    }
  }
}
